using System;
using System.Collections.Generic;
using System.Text;

using System.Text.RegularExpressions;

using NUnit.Framework;

using NSimpleDB.Service.Contract;
using NSimpleDB.Service.Amazon;

namespace test.Service.Amazon.online
{
    [TestFixture]
    public class test
    {
        // store your amazon keys in the app.config
        private string CreateOnlineConnectionString()
        {
            return string.Format("accessKeyId={0};secretAccessKey={1}",
                System.Configuration.ConfigurationManager.AppSettings["accessKeyId"],
                System.Configuration.ConfigurationManager.AppSettings["secretAccessKey"]);
        }


        [Test]
        public void testAnalyseConnectionString()
        {
            AmazonSimpleDBService db = new AmazonSimpleDBService();
            Dictionary<string, string> args = db.AnalyseConnectionString("accessKeyId=a+bc;secretAccessKey=xy+z");
            Assert.AreEqual(2, args.Count);
            Assert.AreEqual("a+bc", args["accessKeyId"]);
            Assert.AreEqual("xy+z", args["secretAccessKey"]);
        }


        [Test]
        public void testCreateSimpleDBProxy()
        {
            AmazonSimpleDBService db = new AmazonSimpleDBService();
            Assert.AreEqual("AmazonSimpleDBMock", db.CreateSimpleDBProxy("").GetType().Name);
            Assert.AreEqual("AmazonSimpleDBClient", db.CreateSimpleDBProxy(this.CreateOnlineConnectionString()).GetType().Name);
        }


        [Test]
        public void testCreateDomain()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                s.CreateDomain("MyDomain");

                ISimpleDBDashbord dashboard = s as ISimpleDBDashbord;
                ISimpleDBResponseMetaData rmd = dashboard.LastResponseMetaData;
                Assert.AreNotEqual("", rmd.RequestId);
                Console.WriteLine("create domain, requestid: " + rmd.RequestId);
                Assert.AreNotEqual("", rmd.BoxUsage);
                Console.WriteLine("  box usage: " + rmd.BoxUsage);
            }
        }


        [Test]
        public void testDeleteDomain()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                s.CreateDomain("MyDomain");
                s.DeleteDomain("MyDomain");

                ISimpleDBDashbord dashboard = s as ISimpleDBDashbord;
                ISimpleDBResponseMetaData rmd = dashboard.LastResponseMetaData;
                Assert.AreNotEqual("", rmd.RequestId);
                Console.WriteLine("delete domain, requestid: " + rmd.RequestId);
                Assert.AreNotEqual("", rmd.BoxUsage);
                Console.WriteLine("  box usage: " + rmd.BoxUsage);
            }
        }


        [Test]
        public void testListDomains()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                for (int i = 0; i < 10; i++)
                    s.CreateDomain("mydomain" + i.ToString());

                string[] resultset;
                string nextToken = null;
                resultset = s.ListDomains(100, ref nextToken);

                ISimpleDBDashbord dashboard = s as ISimpleDBDashbord;
                ISimpleDBResponseMetaData rmd = dashboard.LastResponseMetaData;
                Assert.AreNotEqual("", rmd.RequestId);
                Console.WriteLine("list domains, requestid: " + rmd.RequestId);
                Assert.AreNotEqual("", rmd.BoxUsage);
                Console.WriteLine("  box usage: " + rmd.BoxUsage);

                Assert.IsNull(nextToken);
                Assert.AreEqual(10, resultset.Length);

                resultset = s.ListDomains(2, ref nextToken);
                DumpResultset(resultset);
                Console.WriteLine(nextToken);
                Assert.IsNotNull(nextToken);
                Assert.AreEqual(2, resultset.Length);
                resultset = s.ListDomains(5, ref nextToken);
                DumpResultset(resultset);
                Console.WriteLine(nextToken); 
                Assert.IsNotNull(nextToken);
                Assert.AreEqual(5, resultset.Length);
                resultset = s.ListDomains(ref nextToken);
                DumpResultset(resultset);
                Console.WriteLine(nextToken); 
                Assert.IsNull(nextToken);
                Assert.AreEqual(3, resultset.Length);

                resultset = s.ListDomains();
                Assert.IsNull(nextToken);
                Assert.AreEqual(10, resultset.Length);
            }
        }


        [Test]
        public void testPutGet()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                s.CreateDomain("MyDomain");

                s.PutAttributes("MyDomain", "1", new SimpleDBAttribute("a", "av1"), 
                                                 new SimpleDBAttribute("a", "av2"),
                                                 new SimpleDBAttribute("b", "bv"));

                ISimpleDBAttribute[] attributes;
                attributes = s.GetAttributes("MyDomain", "1", "b");
                Assert.AreEqual(1, attributes.Length);
                Assert.AreEqual("b", attributes[0].Name);
                Assert.AreEqual("bv", attributes[0].Value);

                attributes = s.GetAttributes("MyDomain", "1", "a");
                Assert.AreEqual(2, attributes.Length);
                Assert.AreEqual("a", attributes[0].Name);
                Assert.AreEqual("av1", attributes[0].Value);
                Assert.AreEqual("a", attributes[1].Name);
                Assert.AreEqual("av2", attributes[1].Value);

                attributes = s.GetAttributes("MyDomain", "1", "a", "b");
                Assert.AreEqual(3, attributes.Length);

                attributes = s.GetAttributes("MyDomain", "1", "c");
                Assert.AreEqual(0, attributes.Length);

                attributes = s.GetAttributes("MyDomain", "1");
                Assert.AreEqual(3, attributes.Length);

                attributes = s.GetAttributes("MyDomain", "99");
                Assert.AreEqual(0, attributes.Length);
            }
        }


        [Test]
        public void testDelete()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                s.CreateDomain("MyDomain");

                s.PutAttributes("MyDomain", "1", new SimpleDBAttribute("a", "av1"),
                                                 new SimpleDBAttribute("a", "av2"),
                                                 new SimpleDBAttribute("b", "bv"));

                ISimpleDBAttribute[] attributes;
                attributes = s.GetAttributes("MyDomain", "1");
                Assert.AreEqual(3, attributes.Length);

                s.DeleteAttributes("MyDomain", "1", "b");
                attributes = s.GetAttributes("MyDomain", "1");
                Assert.AreEqual(2, attributes.Length);

                s.DeleteAttributes("MyDomain", "1", new SimpleDBAttribute("a", "av1"));
                attributes = s.GetAttributes("MyDomain", "1");
                Assert.AreEqual(1, attributes.Length);
                Assert.AreEqual("av2", attributes[0].Value);

                s.DeleteAttributes("MyDomain", "1");
                attributes = s.GetAttributes("MyDomain", "1");
                Assert.AreEqual(0, attributes.Length);
            }
        }


        [Test]
        public void testQuery()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                s.CreateDomain("MyDomain");

                s.PutAttributes("MyDomain", "1", new SimpleDBAttribute("a", "av1"),
                                                 new SimpleDBAttribute("a", "av2"),
                                                 new SimpleDBAttribute("b", "bv"));
                s.PutAttributes("MyDomain", "2", new SimpleDBAttribute("a", "av2"),
                                                 new SimpleDBAttribute("a", "av3"),
                                                 new SimpleDBAttribute("b", "bv2"));
                s.PutAttributes("MyDomain", "3", new SimpleDBAttribute("a", "av3"),
                                                 new SimpleDBAttribute("a", "av4"),
                                                 new SimpleDBAttribute("b", "bv2"),
                                                 new SimpleDBAttribute("b", "bv3"));

                string nextToken = null;

                //List<string> items;
                //AmazonSimpleDBService db = (s as AmazonSimpleDBService);
                //items = db.RawQuery("MyDomain", "['a' STARTS-WITH 'av']", 1, ref nextToken);
                //DumpItems(items, s);
                //Console.WriteLine(nextToken);
                //items = db.RawQuery("MyDomain", "['a' STARTS-WITH 'av']", 1, ref nextToken);
                //DumpItems(items, s);
                //Console.WriteLine(nextToken);
                //return;
                
                string[] itemNames;
                itemNames = s.Query("MyDomain", "['a'='av1' or 'a'='av3'] union ['b'='bv3']", 100, ref nextToken);
                Assert.AreEqual(3, itemNames.Length);
                Assert.IsNull(nextToken);

                itemNames = s.Query("MyDomain", "['a' starts-with 'av2']", 1, ref nextToken);
                DumpItems(itemNames, s);
                Assert.IsNotNull(nextToken);
                Assert.AreEqual(1, itemNames.Length);
                itemNames = s.Query("MyDomain", "['a' starts-with 'av2']", 2, ref nextToken);
                DumpItems(itemNames, s);
                Assert.IsNull(nextToken);
                Assert.AreEqual(1, itemNames.Length);

                itemNames = s.Query("MyDomain", "['a'='av2']");
                DumpResultset(itemNames);
                DumpItems(itemNames, s);
                Assert.AreEqual(2, itemNames.Length);

                itemNames = s.Query("MyDomain", "['b' starts-with 'bv2']");
                DumpResultset(itemNames);
                DumpItems(itemNames, s);
                Assert.AreEqual(2, itemNames.Length);
                
                itemNames = s.Query("MyDomain", "['a'='av2'] intersection ['b'='bv2']");
                DumpResultset(itemNames);
                Assert.AreEqual(1, itemNames.Length);
                Assert.AreEqual("2", itemNames[0]);

                itemNames = s.Query("MyDomain", "['a' = 'av2']");
                DumpResultset(itemNames);
                Assert.AreEqual(2, itemNames.Length);
            }
        }


        [Test]
        public void testClearAll()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                string[] domainNames = s.ListDomains();
                foreach (string dn in domainNames)
                {
                    Console.WriteLine("del domain: " + dn);
                    s.DeleteDomain(dn);
                }
                DumpResultset(s.ListDomains());
            }
        }


        [Test]
        public void testExceptionDashboard()
        {
            using (ISimpleDBService s = new AmazonSimpleDBService(this.CreateOnlineConnectionString()))
            {
                try
                {
                    s.GetAttributes("XYZ", "abc");
                }
                catch
                {
                    ISimpleDBDashbord dashboard = (s as ISimpleDBDashbord);
                    Assert.IsNull(dashboard.LastResponseMetaData);
                    ISimpleDBExceptionData ed = dashboard.LastExceptionData;
                    Console.WriteLine(ed.BoxUsage);
                    Console.WriteLine(ed.ErrorCode);
                    Console.WriteLine(ed.ErrorType);
                    Console.WriteLine(ed.Message);
                    Console.WriteLine(ed.RequestId);
                    Console.WriteLine(ed.StatusCode);
                    Console.WriteLine(ed.Xml);
                }
            }
        }


        private void DumpResultset(string[] rs)
        {
            Console.WriteLine("======");
            Console.WriteLine("resultset: ");
            if (rs != null)
                for (int i = 0; i < rs.Length; i++)
                    Console.WriteLine("{0}: {1}", i, rs[i]);
            Console.WriteLine("======");
        }

        private void DumpItems(IEnumerable<string> rs, ISimpleDBService s)
        {
            Console.WriteLine("---------------");
            foreach (string itemName in rs)
            {
                Console.WriteLine("item {0}", itemName);
                ISimpleDBAttribute[] attributes = s.GetAttributes("MyDomain", itemName);
                foreach (ISimpleDBAttribute a in attributes)
                    Console.WriteLine("  {0}={1}", a.Name, a.Value);
            }
        }
    }
}
